How it's wired Tepna
← the -Dex suite · node wiring

❤️ECGDex

ECGDex is the suite’s most precise cardiac receptor — it senses one signal, the heart’s electrical activity, and computes everything from raw µV samples. It is authoritative for HRV magnitude: chest ECG owns that signal until its own quality gate trips.

Signal sensed
Raw ECG (µV)≈130 Hz single lead
Device
Polar H10chest strap · via Polar Sensor Logger
Input format
Polar Sensor Logger CSV/TXTstreamed in a Web Worker
Produces
Full HRV + morphology→ ganglior.node-export
01 — WHAT IT'S FOR

A single-signal receptor

Read the suite as a reflex arc: receptors → relay → integration → insight. ECGDex is an afferent receptor — it does exactly one transduction well and reports inward. It never reaches into another node; cross-signal work happens only through the Ganglior export, consumed by the Integrator.

🧠
One signal per node. ECGDex senses raw ecg (µv) and nothing else. If you’re tempted to sense a second signal, that’s a second node — fusion is the Integrator’s job, never a receptor’s.
02 — THE WIRING

The file stack

ECGDex is built from external *.js files referenced by ECGDex.src.html and bundled to a standalone ECGDex.html. Dependencies point downhill only — UI → DSP → Core — and each file owns exactly one job. Edit the .js + .src.html, never the bundle; re-bundle after changes.

DSP
ecgdex-dsp.jsDSP
The signal engine: 5–15 Hz band-pass → Pan–Tompkins R-peak detection → sub-sample refinement → per-beat SQI gate → full HRV suite + CVHR + ECG-derived respiration + sleep staging.
ecgdex-morph.jsDSP
The “second half” of single-lead ECG: median-beat template, QRS/QT/QTc/PR delineation, beat classification (PVC/PAC), ectopy burden, and an AF screen from RR irregularity.
ecgdex-profile.jsDSP
ANS readiness hero, projected ANS-age, apnea risk from CVHR, HRV-adjusted VO₂max. No BP fields — ECG alone has no pulse wave.
Core
kernel-constants.jsCore · shared
The frozen physiology kernel — one source of truth for every cross-fleet threshold, plus a content-derived hash stamped into each export so two bundles built on different rulebooks can’t silently “agree” when fused.
ganglior-provenance.jsCore · shared
Loaded first — installs the read-hook that makes every export attributable to the exact code + inputs that produced it (the buildHash provenance stamp). 100% local.
metric-registry.jsCore · shared
The shared half of the evidence system: the badge SHAPE, depth tiering and the injected badge CSS. The per-node registry below supplies the DATA, so a Validated dot looks identical in every node.
crossnight-envelope.jsCore · shared
The shared, versioned shape (ganglior.crossnight v1.0) every node emits and the Integrator reads — the container, not the math (the local crossNight() stats stay per-node).
ecgdex-registry.jsCore
Per-metric DATA map (label/unit/goodDirection/depth/evidence) mirroring the cross-night envelope defs so registry and envelope never diverge.
Render · UI
ecgdex-render.jsRender · UI
ECGScope canvas (a min/max envelope pyramid that never subsamples R-peaks away) plus hand-rolled SVG charts: tachogram, Poincaré, hypnogram, CVHR, rMSSD trend.
App · glue
ecgdex-app.jsApp · glue
Streaming ingest via a Blob-built Web Worker, the synthetic generator, multi-recording model, pipeline orchestration and all exports.
Fusion · export
ecgdex-cross.jsFusion · export
Multi-recording trend / z-score / significance math — the byte-identical suite cross helper.
🕒
The Clock Contract. ECGDex stamps every record as floating wall-clock tMs (local civil time encoded as if UTC) and reads it back with getUTC* — so the recording reads identically in any viewer’s timezone, and two devices recording the same minute land on the same tMs. parseTimestamp is duplicated locally by design.
03 — HOW IT'S ACHIEVED

From file drop to Ganglior event

The pipeline is the same shape across the suite: ingest → parse on the canonical clock → compute in DSP → grade & render in UI → emit onto the bus. No number is computed in the render layer; it asks DSP for the value and the registry for how to show it.

Stream the recording

Drop the Polar Sensor Logger ECG export (or generate a synthetic night). Samples are parsed off the main thread in a Web Worker so the UI stays live.

ecgdex-app.js → Worker (Blob)

Band-pass + detect beats

A 5–15 Hz band-pass isolates the QRS energy; Pan–Tompkins finds R-peaks, then a parabolic vertex refines each to sub-sample precision.

ecgdex-dsp.js → panTompkins()

Gate by signal quality

A per-beat SQI gate (flatline, kurtosis, two-detector agreement, RR plausibility) excludes unreliable beats; correction rate and % analyzable are reported.

SQI gate → NN interpolation

Compute HRV + morphology

Clean RR drives the full HRV suite (time/Poincaré/Lomb–Scargle/DFA/SampEn); morph.js adds QT/QTc, ectopy and the AF screen.

ecgdex-dsp.js + ecgdex-morph.js

Emit onto Ganglior

Export autonomic-surge and arrhythmia events with absolute tMs — the corroboration other nodes (OxyDex, CPAPDex) borrow.

ganglior.node-export
04 — HOW MUCH TO TRUST IT

The evidence ladder

Every metric ECGDex surfaces carries an evidence grade — a non-hue badge whose fill is the confidence ladder: solid bullseye for a raw reading, down to a dashed ring for a friendly estimate. A measurement and a projection must never look alike. Grades live in ecgdex-registry.js, the one source of truth.

Measured Mean HR · step count · coverage · % analyzable · beat-correction % · SQI · ectopy count
Validated rMSSD · SDNN · ln rMSSD · QTc · SD1 · SD2 (gold-standard RR HRV)
Emerging CVHR apnea screen · EDR respiration · cardiorespiratory sleep staging · AF screen
Experimental Composite autonomic indices — directional only
Heuristic ANS-age · VO₂max estimate
05 — LIMITATIONS & CONSIDERATIONS

What it can and can't say

Honesty is architectural: a guess is never dressed as a measurement, a missing value stays null rather than fabricated, and confidence is kept separate from signal quality. The node-specific caveats:

Single lead ≠ 12-leadlimitation

Morphology (QT, ST, axis) is directional within-subject trend only. A single chest lead cannot replace a diagnostic 12-lead ECG.

P-wave is weak at 130 Hzcaution

The AF screen reads RR irregularity (ΔRR entropy + CV), not P-wave morphology. It is a screen, not an arrhythmia diagnosis.

Never subsample the waveformnote

ECGScope draws a multi-resolution min/max envelope pyramid — plain decimation would alias R-peaks away and corrupt the read.

Authority is quality-gatedby design

ECG owns HRV magnitude — but a tripped SQI gate yields to a clean PPG/oximetry backup rather than reporting a confident wrong number.

06 — HOW TO USE IT

For the curious, and for the next coder

📂

Open the instrument

ECGDex is one self-contained file. Open ECGDex.html in any browser — online, offline, or from file://. Nothing installs, nothing phones home.

Open ECGDex →
📥

Drop your recording

Drag a Polar H10 export (polar sensor logger csv/txt) onto the upload zone. It’s read in-browser and turned into metrics on your device alone.

🎚️

Read at your depth

Start in Core for the headline readiness and a plain-language line. Step up to Advanced for full tables and charts, or Research for composites and the full dump. Each metric’s evidence dot tells you how far to trust it.

🔀

Export onto Ganglior

Export a ganglior.node-export JSON to feed the Integrator, or to upgrade a peer node’s read. Events carry a wall-clock t; consumers reconstruct absolute time from the recording start.

ECGDex reference guide →
🛠️

If you’re changing it

Edit the ecgdex-*.js files or ECGDex.src.htmlnever the bundled ECGDex.html — then re-bundle. Run Dex-Test-Suite.html until all-green, and verify-provenance.html after re-bundling.